home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / os2 / srefv112.zip / DOSEARCH.80 < prev    next >
Text File  |  1996-05-11  |  26KB  |  700 lines

  1. /****************************************************************/
  2. /* generic text file  search utility for SREFILTR package.  Designed to be used
  3. as a directly requested file searcher, or as part of a "searchable index" process.
  4.  
  5.  
  6.   ---- Invoking DOSEARCH ---
  7.  
  8.   When called directly, the "request string"    should have the form:
  9.        DOSEARCH?option_1=val_1&option_2=val_2&etc.
  10.    where the file to be searched, the search string, and other options are returned
  11.    in the option_n list.
  12.    In this case, list0=option_1=val_1&option_2=val_2&etc.
  13.    Note that a FILE and a SEARCH option should always be present.
  14.  
  15.  --------  DOSEARCH options -----
  16.  
  17. DOSEARCH looks at "paragraphs".  By default, a paragraph is defined as being
  18. all text between blank lines.  Alternatively, one can define paragraphs as single lines,
  19. or as delimited by any arbitrary character sequence (see options section below).
  20.  
  21. A search string is comprised of "targets" There are two kinds of targets: subwords and phrases.
  22.   Each space delimited entry in the search string is treated as a seperate "subwords".
  23.   Phrases are delimited by ( xx yy zz ); phrases must be matched precisely.
  24.  
  25. Search algorithims.  There are two modes:
  26.  Simple mode with highlighting.  Two "meta commands" and 4 "target specific"
  27.  instructions are recognized.  
  28.         Meta commands are signified by *& or *\ at the beginning of the search string.
  29.              *&  means "find paragraphs that match ALL targets in the search string"
  30.              *\  means "find paragraphs that match NONE of the targets in the search string"
  31.      If there are no meta commands, the following "target specific" commands are recognized.
  32.           &  means "paragraphs MUST have this target"
  33.           |   means "accept paragraph if it has this target"
  34.               Note that | is the default (assumed if no target specific command entered).
  35.           \ means "paragraph must NOT have this target" 
  36.           % means "accept paragraph if it does NOT have this target"
  37.  
  38.     Summarizing: to be a "found" paragraph:
  39.       Test 1a) Any | must be present,    or
  40.             1b)   All of the % are missing
  41.             (if no % appears, then 1b is ignored)
  42.       Test 2a) If pass test 1, then
  43.             2b)   None of the \ can be present, and
  44.                All of the & must be present
  45.      If present, all & and | targets will be highlighted
  46.  
  47.  Logical expression mode without highlighting.
  48.       The user enters a logical expression using the following operators:
  49.           & = AND  ,  | = OR ,    \ = not ,   @ = xor , ( ) to group expressions.
  50.       A sequence of words without any operators is treated as a phrase -- to
  51.       treat each word as a seperate subword, put ( ) around each one.
  52.       Basically, when using this mode, be liberal in your use of ( ).
  53.  
  54. Options (included in the ALIAS definition, or generated by a form):
  55.        Options are included after the searchstring, seperated by &.  Typically,
  56. they would be placed there by a form, not by an <ISINDEX> response.  Form of the
  57. options is option_name=option_value&option_Nam2=option_value2&...
  58.  
  59.        DELIM :  The paragraph delimiter.
  60.                    Blank or 0= blank lines   (the DEFAULT)
  61.                    $  = Each line is a paragraph
  62.                    other  = User specified delimiter
  63.        LINE : Maximum number of lines to display in a paragraph. If 0, no lines displayed
  64.               just summary.   Default is display all lines.
  65.        NUM : YES=Display the line or paragraph number, NO=Don't (Default=YES)
  66.        BAR:  YES= Seperate each paragraph/line by a horizontal bar, NO=Don't (Default=YES)
  67.        EXPERT: YES= Use "logical expression mode", NO=Use simple mode (Default=NO)
  68.       HIGHLIGHT: YES= Highlight mathes, NO=DON'T (only if non-expert mode)
  69.        FILE or FILES:  Additional files to search (can include wildcards)
  70.        SEARCH: Use this as the searchlist -- required for FORM based submittal,
  71.                 overrides default (first thing after the ? and before the first &) if
  72.                 a ISINDEX based submittal)
  73.                 Note: SEARCHFOR  STRING NEEDLE TARGET can be used instead of SEARCH
  74.        CASE : If YES, then search is case sensitive (default is no)
  75.  
  76.  
  77. Note: a FILE (or FILES) and a SEARCH option should always be present.
  78.  
  79. Also, DOSEARCH will detect whether it has been called as the result of a 
  80. direct request (say, from a FORM) and not as an alias,.
  81. If called directly, the SEARCH and FILE options MUST be present.
  82.  
  83. */
  84. /***********************************************************/
  85.  
  86.  
  87.  
  88. /*PARSE ARG   ddir,tempfile,sel,list0,verb,uri */
  89. parse arg ddir,tempfile,sel,list0,verb,uri,user,basedir,workdir,privset,infiles
  90.  
  91.  
  92. parse var infiles params0 ',' access_file ',' userfile ',' virtual_file ',' alias_file ',' sendfile_file
  93. userfile=strip(userfile) ; access_file=strip(access_file); 
  94. virtual_file=strip(virtual_file) ; alias_file=strip(alias_file)
  95. sendfile_file=strip(sendfile_file)
  96.  
  97.  
  98. list0=translate(list0, ' ', '+'||'090a0d'x)  /* Whitespace, etc. */
  99.  
  100. ddir=translate(ddir,'\','/')
  101. ddir=strip(ddir,'t','\')||'\'
  102.  
  103. macrospace_input=strip(params0)
  104.  
  105. parse var uri index_htm '?' listuri
  106. index_htm=translate(strip(index_htm,,'/'))
  107.  
  108.  
  109. options2=" " ; options=" "
  110.  gotss=0
  111.  searchlist=" "
  112. ifiles=0
  113.  
  114.  options=list0
  115.  
  116. para_delim=""
  117. maxdisp=1000000
  118. show_number=1
  119. show_bar=1
  120. expert_mode=0
  121. check_case=0
  122. highlight=1
  123.  
  124. /* get option */
  125. do until options=""
  126.   parse var options an1 '&' options
  127.   parse var  an1 aname '=' avalue
  128.   aname0=aname ; aname=translate(aname)
  129.   avalue0=avalue ; 
  130.   avalue=translate(avalue,' ','+'||'0d0a09'x)
  131.   avalue0=packur(avalue)
  132.   avalue=translate(avalue0)
  133.   avalue=translate(avalue,' ','"')
  134.   avalue=translate(avalue,' ',"'")
  135.  
  136.  
  137.   select
  138.      when pos("DELIM",aname)> 0 then 
  139.          para_delim=avalue0
  140.   
  141.      when pos("LINE",aname)> 0 then
  142.          if datatype(avalue)="NUM" then
  143.               maxdisp=avalue
  144.      when pos("NUM",aname)>0 then
  145.          if left(avalue,1)="N" | avalue=0 then  show_number=0
  146.      when pos("BAR",aname)>0 then
  147.          if left(avalue,1)="N" | avalue=0 then  show_bar=0
  148.      when pos('EXPERT',aname)>0 then
  149.              if left(avalue,1)="Y" | avalue=1 then   expert_mode=1
  150.      when pos('HIGHLIGHT',aname)>0 then do
  151.                 if abbrev(avalue,'Y')=1 then highlight=1
  152.                 if abbrev(avalu,'N')=1 then highlight=0
  153.      end
  154.      when abbrev(aname,'FILE')=1 then do
  155.              if avalue<>"" then do
  156.                  ifiles=ifiles+1
  157.                  files.ifiles=avalue
  158.              end
  159.      end
  160.  
  161.  
  162.      when pos("CASE",aname)>0 then
  163.          if left(avalue,1)="Y" | avalue=1 then  check_case=1
  164.  
  165.      when wordpos(aname,'SEARCH SEARCHFOR STRING NEEDLE TARGET')>0 then do
  166.                searchlist=avalue0
  167.       end
  168.      otherwise
  169.   end
  170. end
  171.  
  172. /* note: default para_delim is "blank lines" */
  173.  
  174. searchlist=translate(searchlist,' ','+'||'000d0a09'x)
  175. searchlist=packur(searchlist)                   /* do it now, to revitalize &'s */
  176. if left(para_delim,1)='"' & right(para_delim,1)='"' then 
  177.     para_delim=strip(para_delim,,'"')
  178. if para_delim="" then para_delim=" "
  179. if para_delim=0 then para_delim=" "
  180. crlf = '0d0a'x
  181.  
  182.  
  183. /* ----------------- Section to do a search   -------------- */
  184.  
  185. /* If here, we have some  stuff in the request string (after a ? )
  186.    (either supplied explicitly, or  as a response to the searchable index created above */
  187.  
  188.  call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  189.  CALL LINEOUT TEMPFILE,'<html> <head> <title> Results of search </title>  </head>'
  190.  call lineout tempfile,'<body>'
  191.  
  192.  
  193. /* create list of files to search */
  194. files_todo=0
  195. do ido=1 to ifiles
  196.       afilenam=sref_do_virtual(ddir,files.ido,macrospace_input,virtual_file)
  197.       if afilenam=0 then iterate               /* error */
  198.       eek=sysfiletree(afilenam,'aflist','F')   /* check for */
  199.       if eek<>0 then iterate            /* error */
  200.       do ido1=1 to aflist.0             /* any matches */
  201.          files_todo=files_todo+1
  202.          file_list.files_todo=word(aflist.ido1,words(aflist.ido1)) /* grab name */
  203.          file_list.files_todo.original=files.ido
  204.       end
  205. end
  206. ith_file=0
  207.  
  208. if files_todo>0 then
  209.    call lineout tempfile,' <h3> Number of files to search: ' files_todo '</h3> <hr>'
  210.  
  211. NEXTFILE:               /* JUMP HERE TO READ NEXT FILE  *****************    */
  212.  
  213. ith_file=ith_File+1
  214. filename=strip(file_list.ith_file)
  215. afilenam=filename
  216. aoriginal=file_list.ith_file.original
  217. goober=filespec('n',filename)
  218.  
  219. /* read in this target file (filename) into filelines stem variable */
  220. filelines.0=0
  221. getit=0
  222.  
  223.  
  224. if filename<>"" then do                 /* check for no filename */
  225.  select
  226.    when para_delim=" " then do
  227.         getit=fileread(afilenam,'filelines',,'e')
  228.    end
  229.    when para_delim="$" then do
  230.         getit=fileread(afilenam,'filelines',,'e')
  231.    end
  232.   otherwise do
  233.        getit=grab_file_lines(afilenam,20,para_delim)
  234.   end
  235.  end
  236.  say " DOSEARCH will examine:" afilenam "(# entries= " getit 
  237.  
  238. end             /* filename<>"" */
  239.  
  240. /* problem ... */
  241. if getit <= 0 then   do             /*fatal error */
  242.     call lineout tempfile,'<h2> No search target </h2> '
  243.     say " No such file " filename
  244.     call lineout tempfile,' <p> <strong> Can not find file: <strong> ' filename
  245.     call lineout tempfile,'</body> </html>'
  246.   call lineout tempfile
  247.  
  248.     return 'FILE  ERASE TYPE text/html NAME ' tempfile
  249. end
  250.  
  251.  
  252.  
  253. /* look for meta flags (they over ride individual  flags*/
  254. matchall=0 ; matchnone=0
  255. if word(searchlist,1)='*&' then do
  256.   matchall=1
  257.   searchlist=delword(searchlist,1,1)
  258. end
  259. else if word(searchlist,1)="*\" then do
  260.   matchnone=1
  261.   searchlist=delword(searchlist,1,1)
  262. end
  263.  
  264. if searchlist="" then do                /*missing searchlist */
  265.   call lineout tempfile,'<h2> No search list </h2> '
  266.    say " No searchlist specified."
  267.    call lineout tempfile,' <p> <strong> No search list specified  <strong> ' 
  268.    call lineout tempfile,'</body> </html>'
  269.   call lineout tempfile
  270.  
  271.    return 'FILE  ERASE TYPE text/html NAME ' tempfile
  272. end
  273.  
  274.  
  275. /* write some else, basic facts .. */
  276.  call lineout tempfile,'<h2> Results of  search  </h2> '
  277.  call lineout tempfile,' File searched: <strong> ' goober ' </strong> '
  278.  if pos('*',aoriginal)>0 | pos('?',aoriginal)>0 then
  279.         call lineout tempfile,' <em> ( ' aoriginal ' ) </em> '
  280.  call lineout tempfile,' <br>Search pattern: <strong> ' searchlist ' </strong> '
  281.  if matchall=1 then call lineout tempfile, '<em> (must match all) </em> '
  282.  if matchnone=1 then call lineout tempfile, '<em> (must match none) </em> '
  283.  
  284.  call lineout tempfile,' <hr width= 75%>'
  285.  
  286. /* before extracting phrases, make sure & / ( and ) are spaced out */
  287. searchlist=sref_replacestrg(searchlist,'&',' & ','ALL') ;
  288. searchlist=sref_replacestrg(searchlist,'\',' \ ','ALL') ; 
  289. searchlist=sref_replacestrg(searchlist,'(',' ( ','ALL') ;
  290. searchlist=sref_replacestrg(searchlist,')',' ) ','ALL') ; 
  291. searchlist=sref_replacestrg(searchlist,'|',' | ','ALL') ;
  292.  
  293. if expert_mode=0 then do                /* fairly search scheme */
  294.     ith=get_searchfor(searchlist,check_case)   /* searchfor. and cond. are exposed */
  295.  
  296.     dispdetails=1          /* if a NOT or AND exists, set to 0 (since individual details are inaccurate*/
  297.     /* If there are global conditins, overwrite any spurious local conditions */
  298.     do mm=1 to searchfor.0
  299.       select
  300.         when matchall=1 then
  301.            cond.mm='AND'
  302.         when matchnone=1 then
  303.            cond.mm='ORNOT'
  304.         otherwise
  305.       end
  306.       if  cond.mm<>"OR" then dispdetails=0
  307.     end
  308. end
  309. else  do            /* expert mode: user enters syntatically correct search command */
  310.    searchlist=expert_parse(searchlist,'HAYSTACK',check_case)
  311. end
  312.  
  313.  
  314.  
  315. change_crlf=0
  316. select                  /* now, create "paragraphs" */
  317.    when para_delim=" " then do   /* the default-- blank lines as delimiters */
  318.       nthpara=build_paras()    /* filelines. and paras. are exposed */
  319.       say " # paragraphs " nthpara
  320.     end
  321.    /* filelines might be lines of the file, or "delimited" blocks
  322.        Note that "user delimited" blocks retain CRLFs. */
  323.     otherwise  do                  /* use each line, or  para_delim literally */
  324.       do mm=1 to filelines.0
  325.           paras.mm.first=mm
  326.           paras.mm.last=mm
  327.       end
  328.       nthpara=filelines.0
  329.       if para_delim<>'$' then change_crlf=1  /* change to <BR> below */
  330.    end
  331.   end
  332.  
  333. /* Now find 'paragraphs' containing the search patterns */
  334.  
  335. nmatch=0
  336. if expert_mode=0 then
  337.   do jj=1 to searchfor.0
  338.      allmatch.jj=0
  339.   end
  340.  
  341. do mm=1 to nthpara
  342.  
  343.    apara=""
  344.    do mm2=paras.mm.first to paras.mm.last   /* create a paragraph */
  345.       apara=apara||' '||filelines.mm2
  346.    end
  347.  
  348. /* -------- see if this paragraph is a hit */
  349.  
  350.  
  351.      if expert_mode=0 then
  352.          gotems=match_para(apara,checK_case)  /* searchfor. cond. mlist. are exposed */
  353.  
  354.      else do
  355.         haystack=apara
  356.         if check_case<>1 then haystack=translate(haystack)
  357.         signal on syntax name oyvey
  358.         interpret 'gotems='||searchlist
  359.         signal off syntax
  360.      end
  361.  
  362.      if gotems=0 then do
  363.        iterate       /* get next paragraph */
  364.      end
  365.  
  366.  
  367. /* if here, got a match. So write out the paragraph */
  368.      nmatch=nmatch+1         /* summary counter */
  369.      if maxdisp=0 then iterate
  370.  
  371.      if para_delim<>'$' then
  372.          if show_number=1 then
  373.             call lineout tempfile,'<h6 align=center>Paragraph #  '  mm ' </h6> '
  374.          else
  375.              call lineout tempfile,'<p>'    /* make space in output doc */
  376.  
  377.       else do
  378.          call lineout tempfile,'<p>'    /* make space in output doc */
  379.      end
  380.  
  381.      writlin=0
  382.   
  383.      do mm2=paras.mm.first to paras.mm.last  /* output original 'lines' */
  384.                     aline=filelines.mm2         /* that comprise the paragraph */
  385.  
  386.           IF EXPERT_MODE=0 THEN
  387.              do mm3=1 to searchfor.0    /* we know that pre is weren't present*/
  388.                if mlist.mm3 =0 then iterate
  389.                if HIGHLIGHT=1 then
  390.                   aline=sref_make_block(searchfor.mm3,aline,'<b>','</b>',check_case) /* highlight matches */
  391.             end         /* Note: expert mode does NOT have highlighting */
  392.  
  393.           if change_crlf=1 then                 /* convert crlf in custom delimited blocks */
  394.               aline= sref_replacestrg(aline,crlf,'<BR>','ALL')
  395.           if para_delim<>'$' then
  396.              call lineout tempfile, aline ' <br>'
  397.           else
  398.              if show_number=1 then call lineout tempfile, '<cite> ' mm2  ' : </cite>  ' aline
  399.              else call lineout tempfile,  aline
  400.  
  401.           writlin=writlin+1
  402.           if writlin>=maxdisp then leave
  403.      end                     /* output lines of the paragraph */
  404.      if para_delim<>'$' & show_bar=1 then
  405.          call lineout tempfile,' <hr width=10% height=5> '
  406.  
  407.      /* jump here if matchall=1 and not all matches */
  408. end                    /* do next paragraph */
  409.  
  410.  
  411. asummary:
  412.   call lineout tempfile,' <hr width= 75%>'
  413.   call lineout tempfile,' <p> <h3> Summary of results: ' goober ' </h3> '
  414.   call lineout tempfile,'  # "paragraphs" = ' nthpara
  415.   if para_delim=" "  para_delim="$" then do
  416.     call lineout tempfile,' <menu> '
  417.     call lineout tempfile,' <li> # of lines = ' filelines.0
  418.     call lineout tempfile,'</menu> '
  419.   end
  420.   else
  421.     call lineout tempfile,'<br> '
  422.  
  423.   call lineout tempfile,'  # paragraphs with matches= ' nmatch
  424.   if dispdetails=1 then do
  425.     call lineout tempfile,'<menu> '
  426.     do mm=1 to searchfor.0
  427.        call lineout tempfile,'<li> ' searchfor.mm ' = ' allmatch.mm
  428.     end
  429.     call lineout tempfile,'</menu> '
  430.   end
  431.  
  432.  if ith_file<files_todo then do                     /* get next file */
  433.       call lineout tempfile,'  <hr> '
  434.       call lineout tempfile,'  <Hr width=5> '
  435.       call lineout tempfile,' <hr> '
  436.  
  437.       signal nextfile
  438. end
  439.  
  440.   call lineout tempfile,'</body>'
  441.   call lineout tempfile,'</html>'
  442.   call lineout tempfile
  443.  
  444.   return 'FILE  ERASE TYPE text/html NAME ' tempfile
  445.  
  446. oyvey:                  /* jump here if bad expert mode */
  447.   call lineout tempfile,'<h3> Bad logical search expression </h2> '
  448.    say " Bad  searchlist specified."
  449.    call lineout tempfile,' <p> <strong> A bad logical expression was specified  <strong> '
  450.    call lineout tempfile,'</body> </html>'
  451.   call lineout tempfile
  452.  
  453.    return 'FILE  ERASE TYPE text/html NAME ' tempfile
  454.  
  455.  
  456.  
  457. /* ----------------------------------------------------------------------- */
  458. /* GET_SEARCHFOR: Create the "search for" list (of things to search for ) */
  459. /* ----------------------------------------------------------------------- */
  460.  
  461. get_searchfor: procedure expose searchfor.  cond.
  462. parse arg searchlist, check_case
  463.  
  464. ith=0
  465. if check_case<>1 then searchlist=translate(searchlist)
  466.  
  467. acondstate='OR'                 /* default state */
  468. mm=0
  469. do until mm=words(searchlist)
  470.    mm=mm+1
  471.    aword=word(searchlist,mm)
  472.    a1a=verify('\&(|%',aword,'m')
  473.    select 
  474.      when a1a=0  then do   
  475.         ith=ith+1
  476.         searchfor.ith=aword
  477.         cond.ith=acondstate
  478.         acondstate='OR'            /* reset to OR */
  479.      end
  480.      when a1a=1 then     /*  Not is an AND NOT */
  481.         acondstate='NOT'
  482.      when a1a=2 then
  483.         acondstate='AND'
  484.      when a1a=4 then            /* included for completeness */
  485.         acondstate='OR'
  486.      when a1a=5 then
  487.         acondstate='ORNOT'
  488.      when a1a=3 then do  /* begin a phrase -- find the first ) to end it */
  489.          ajj=wordpos(')',searchlist,mm)
  490.          if ajj=0 then ajj=words(searchlist)+1
  491.          if ajj>mm+1 then do
  492.             ith=ith+1
  493.             searchfor.ith=' '||subword(searchlist,mm+1,ajj-(mm+1))||' '
  494.             cond.ith=acondstate
  495.          end
  496.          mm=ajj
  497.       end
  498.       otherwise
  499.    end
  500. end
  501. searchfor.0=ith
  502. return ith
  503.  
  504.  
  505. /* -------------------------------------------------------- */
  506. /* BUILD_PARAS: Build paragraphs from lines (blank line delimits a paragraph */
  507. /* -------------------------------------------------------- */
  508.  
  509. build_paras: procedure expose filelines. paras.
  510.   
  511.      apara=0
  512.      nthpara=0
  513.      do mm=1 to filelines.0
  514.        if filelines.mm="" then do
  515.           if apara=1 then do    /* second or more of a series of blank lines */
  516.               paras.nthpara.last=mm-1
  517.              apara=0
  518.           end
  519.         end
  520.         else do
  521.           if apara=0  then do
  522.              nthpara=nthpara+1
  523.              paras.nthpara.first=mm
  524.              apara=1
  525.           end
  526.         end
  527.      end  /* Do filelines.0 */
  528.  
  529.      if apara=1 then paras.nthpara.last=filelines.0
  530.      return nthpara
  531.  
  532. /* ------------------------------------------------------------------- */
  533. /* MATCH_PARA: Does this paragraph match the search string(s)  */
  534. /* ------------------------------------------------------------------- */
  535.  
  536. match_para: procedure expose searchfor. cond. mlist. allmatch.
  537.   parse arg apara , check_case
  538.  
  539.   apara2=apara
  540.   if check_case<>1 then apara2=translate(apara2)
  541.  
  542. /* scan for matches in the paragraph */
  543.     gotems=0 ; numors=0
  544.  
  545.     do nn= 1 to searchfor.0                     /*see how many or conditions there are */
  546.         if cond.nn="OR" then numors=numors+1
  547.         mlist.nn=0
  548.     end
  549.  
  550.     do is=1 to searchfor.0   /*search for targets in this paragraph*/
  551.        joe=pos(searchfor.is,apara2)
  552.  
  553.        if joe=0 & cond.is="AND" then do    /* failure of an "all matches" */
  554.            gotems=0
  555.            leave
  556.        end
  557.        if joe>0 & cond.is="NOT" then do   /* failure of a "not any of these*/
  558.            gotems=0
  559.            leave
  560.        end
  561.        if joe>0 & cond.is="ORNOT"  then do  /* or not condition failed */
  562.            gotems=0
  563.            leave
  564.        end
  565.  
  566. /* if here, no fatal flaw */
  567.       if (joe>0 ) & (pos('NOT',cond.is)=0) then mlist.is=1
  568.  
  569.       if  (joe>0 & cond.is="OR") | (joe=0 & cond.is="ORNOT")  then do
  570.               allmatch.is=allmatch.is+1
  571.               gotems=gotems+1
  572.        end
  573.        if (joe>0 & cond.is="AND" & numors=0) then do  /* if no or conditions.. */
  574.               gotems=gotems+1
  575.               allmatch.is=allmatch.is+1
  576.        end
  577.        
  578.      end
  579.      return gotems
  580.  
  581.  
  582.  
  583.  -------------------------------------------------------------- /
  584. /*  GRAB_FILE_LINES:  Get a file, parse into a "lines" stem variable
  585. .  Read in a file, but first check to see if openable, and if
  586. .  so, open and  read.  After reading, split into logical lines,
  587. .  using the eol character ('0d0a'x  by default), and return
  588. .  each of these lines in the filelines. stem variable.
  589. .  Note: filelines.0 holds # of lines; also, the number of lines
  590. .  is returned (so if 0 returned, failure probably caused by no such file)
  591. .  Usage:
  592. .   filelines.0= 0 ;  nlines=grab_file_lines(afile,30,optional_eol_delimiter)
  593. .   (filelines.1 to filelines.(filelines.0) contain afile)
  594. */
  595. /* ------------------------------------------------------------- */
  596.  
  597. grab_file_lines: procedure expose filelines.
  598.  
  599. parse arg afile, msec, aneol    /* file to get, seconds to wait, eol delimiter */
  600.  
  601. crlf = '0d0a'x
  602.  
  603. if aneol="" then aneol=crlf
  604.  
  605. ause=sref_grab_file(afile,msec)
  606. if ause=0 then                  /* couldn't get it */
  607.   return 0
  608.  
  609. /* got a file, let's parse it */
  610. if filelines.0<>0 then say " Warning: overwriting filelines stem variable "
  611. filelines.0=0
  612. i=0
  613. aneol=strip(aneol)
  614. do until ause=""
  615.   i=i+1
  616.   parse var ause filelines.i (aneol) ause
  617. end
  618. filelines.0=i
  619. return filelines.0
  620.  
  621. /********************************************************************************/
  622. /***********************************/
  623. /* Tim Osborne's fancy logical parser */
  624.  
  625. expert_parse: procedure 
  626.  parse  arg mystring , haystack , check_case
  627.   if check_case<>1 then mystring=translate(mystring)
  628.  
  629.  if haystack="" then haystack="HAYSTACK"
  630.  
  631. /*
  632.   User enters logical search string
  633.  
  634.    User can include any level of nested parentheses to
  635.    override normal order of logical statement.  Parentheses
  636.    are not required however.
  637.  
  638. say 'What are you looking for?'
  639. pull mystring
  640. */
  641.  
  642. mystring='('||mystring||')'
  643. mystring=space(mystring)
  644. if pos('(',mystring)=0 & pos('|',mystring)=0 & pos('\',mystring)=0 & pos('&',mystring)=0 & pos('@',mystring)=0 then do
  645.    mystring='('||mystring||')'
  646.    end
  647. else do
  648.    blanks= pos(' (',mystring)>0 | pos('( ',mystring)>0 | pos(' &',mystring) >0 | pos('& ',mystring)>0 |,
  649.            pos(' |',mystring)>0 | pos('| ',mystring)>0 | pos(' @',mystring) >0 | pos('@ ',mystring)>0 |,
  650.            pos(' \',mystring)>0 | pos('\ ',mystring)>0 | pos(' )',mystring) >0 | pos(') ',mystring)>0
  651.    do while blanks > 0
  652.       if pos(' (',mystring) \=0 then mystring=substr(mystring,1,pos(' (',mystring)-1)||'('||substr(mystring,pos(' (',mystring)+2)
  653.       if pos(' )',mystring) \=0 then mystring=substr(mystring,1,pos(' )',mystring)-1)||')'||substr(mystring,pos(' )',mystring)+2)
  654.       if pos(' |',mystring) \=0 then mystring=substr(mystring,1,pos(' |',mystring)-1)||'|'||substr(mystring,pos(' |',mystring)+2)
  655.       if pos(' &',mystring) \=0 then mystring=substr(mystring,1,pos(' &',mystring)-1)||'&'||substr(mystring,pos(' &',mystring)+2)
  656.       if pos(' @',mystring) \=0 then mystring=substr(mystring,1,pos(' @',mystring)-1)||'@'||substr(mystring,pos(' @',mystring)+2)
  657.       if pos(' \',mystring) \=0 then mystring=substr(mystring,1,pos(' \',mystring)-1)||'\'||substr(mystring,pos(' \',mystring)+2)
  658.       if pos('( ',mystring) \=0 then mystring=substr(mystring,1,pos('( ',mystring)-1)||'('||substr(mystring,pos('( ',mystring)+2)
  659.       if pos(') ',mystring) \=0 then mystring=substr(mystring,1,pos(') ',mystring)-1)||')'||substr(mystring,pos(') ',mystring)+2)
  660.       if pos('| ',mystring) \=0 then mystring=substr(mystring,1,pos('| ',mystring)-1)||'|'||substr(mystring,pos('| ',mystring)+2)
  661.       if pos('& ',mystring) \=0 then mystring=substr(mystring,1,pos('& ',mystring)-1)||'&'||substr(mystring,pos('& ',mystring)+2)
  662.       if pos('@ ',mystring) \=0 then mystring=substr(mystring,1,pos('@ ',mystring)-1)||'@'||substr(mystring,pos('@ ',mystring)+2)
  663.       if pos('\ ',mystring) \=0 then mystring=substr(mystring,1,pos('\ ',mystring)-1)||'\'||substr(mystring,pos('\ ',mystring)+2)
  664.  
  665.            blanks= pos(' (',mystring)>0 | pos('( ',mystring)>0 | pos(' &',mystring) >0 | pos('& ',mystring)>0 |,
  666.               pos(' |',mystring)>0 | pos('| ',mystring)>0 | pos(' @',mystring) >0 | pos('@ ',mystring)>0 |,
  667.               pos(' \',mystring)>0 | pos('\ ',mystring)>0 | pos(' )',mystring) >0 | pos(') ',mystring)>0
  668.     end
  669. end
  670. if lastpos(')',mystring) \= length(mystring) then mystring='('||mystring||')'
  671. mystring=mystring||'*'
  672. pointer=1
  673. notin=1
  674. mychar=substr(mystring,pointer,1)
  675. do until mychar='*'
  676.            if pos(substr(mystring,pointer,1),'()|&@\')=0 & notin then do
  677.               mystring=substr(mystring,1,pointer-1)||'pos('''||substr(mystring,pointer)
  678.               notin=0
  679.               pointer=pointer+4
  680.            end
  681.            else do
  682.               if pos(substr(mystring,pointer,1),'()|&@\')>0 & notin=0 then do
  683.                  mystring=substr(mystring,1,pointer-1)||''',haystack)>0'||substr(mystring,pointer)
  684.                  notin=1
  685.                  pointer=pointer+12
  686.               end
  687.            end
  688.            pointer=pointer+1
  689.            mychar=substr(mystring,pointer,1)
  690. end
  691. mystring=substr(mystring,1,length(mystring)-1)
  692. do while pos('@',mystring)>0
  693.    mystring=insert('&&',mystring,pos('@',mystring))
  694.    mystring=delstr(mystring,pos('@',mystring),1)
  695. end
  696. /*say " mystring: " mystring*/
  697. return mystring
  698.  
  699.  
  700.